package com.crm.jpaandthymeleaf.config.shiro;

import com.crm.jpaandthymeleaf.config.MySimpleByteSource;
import com.crm.jpaandthymeleaf.entity.SysRight;
import com.crm.jpaandthymeleaf.entity.SysUser;
import com.crm.jpaandthymeleaf.service.ISysRightService;
import com.crm.jpaandthymeleaf.service.ISysUserService;
import com.crm.jpaandthymeleaf.service.LockLoginService;
import com.crm.jpaandthymeleaf.web.exception.LoginException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.util.List;

/**
 * 安全数据源
 * @author 周敬
 * @version 1.0
 * @packageName com.crm.jpaandthymeleaf.config
 * @fileName MyShiroRealm
 * @createTime 2021/12/22-16:42-星期三
 * @lastModify 2021/12/22-16:42-星期三
 */
public class MyShiroRealm extends AuthorizingRealm {

    @Resource
    private ISysUserService userService;
    @Resource
    private ISysRightService rightService;
    @Autowired
    private LockLoginService lockLoginService;

    final String MANAGER = "管理员";

    /**
     * 获取权限信息（角色和权限）
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("调用MyShiroRealm.doGetAuthorizationInfo获取信息！");

        //获得权限信息
        SysUser user = (SysUser) principalCollection.getPrimaryPrincipal();

        //简单的授权信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //添加角色
        info.addRole(user.getRole().getRoleName());
        //根据当前角色的角色查询出角色的所有权
        List<SysRight> rights = rightService.findSysRightByRole(user.getRole());
        for (SysRight right : rights) {
            //添加当前用户的权限
            System.out.println("当前用户登录的角色是：【" + user.getUsrName() + "】，拥有【" + right.getRightText() + "】的权限");
            info.addStringPermission(right.getRightText());
        }
        return  info;
    }

    /**
     * 获取身份信息
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("调用MyShiroRealm.doGetAuthenticationInfo获取信息！");
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        String username = token.getUsername();

        //首先判断用户是否已被锁定
        if(lockLoginService.isLock(username)){
            throw new LockedAccountException("该账户已经被锁定");
        }
        //用户的登录记录次数叠加，用户登录成功后会将其清零
        try {
            lockLoginService.checkLogin(username);
        } catch (LoginException e) {
            //用户登录记录次数超过5次，将锁定1一个小时
            lockLoginService.lock(username);
           throw new LockedAccountException("账户锁定");
        }

        SysUser user = userService.getUserByUserName(username);
        if(user==null){
            //账号错误
            throw new UnknownAccountException();
        }
        if(user.getUsrFlag()==null || user.getUsrFlag().intValue()==0){
            //账号锁定
            throw new LockedAccountException();
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                user,                                       //身份（根据用户名查询数据库获取得到用户）
                user.getUsrPassword(),                      //凭证（查询数据库获取得到密码）
//                ByteSource.Util.bytes(user.getUsrName()),   //加密使用salt
                new MySimpleByteSource(user.getUsrName()),
                getName()                                   //Realm对象的名称
        );
        //.....
        //返回身份信息
        return info;
    }

    /**
     * 清空当前认证用户权限的缓存
     */
    public void clearMyCachedAuthorizationInfo(){
        clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}
